/*
所有权有以下三条规则：

Rust 中的每个值都有一个变量，称为其所有者。
一次只能有一个所有者。
当所有者不在程序运行范围时，该值将被删除。
*/

{
    // 在声明以前，变量 s 无效
    let s = "runoob";
    // 这里是变量 s 的可用范围
}
// 变量范围已经结束，变量 s 无效


fn main() {
    let x = 5;
    let y = x;
    println!("{} - {}",x,y)  // 5 - 5
}

let s1 = String::from("hello");
let s2 = s1; 
println!("{}, world!", s1); // 错误！s1 已经失效,s1资源已经被释放

// 所以非基本类型的数据需要用到克隆
fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();
    println!("s1 = {}, s2 = {}", s1, s2);
}

// ----------------------- 涉及函数的所有权机制 -----------------
fn main() {
    let s = String::from("hello");
    // s 被声明有效

    takes_ownership(s);
    // s 的值被当作参数传入函数
    // 所以可以当作 s 已经被移动，从这里开始已经无效
    //println!("{}",s);  // 

    let x = 5;
    // x 被声明有效

    makes_copy(x);
    // x 的值被当作参数传入函数
    // 但 x 是基本类型，依然有效
    // 在这里依然可以使用 x 却不能使用 s
    println!("{}",x);   // 这里的x不会被释放,因为它是基本类型
} // 函数结束, x 无效, 然后是 s. 但 s 已被移动, 所以不用被释放


fn takes_ownership(some_string: String) {
    // 一个 String 参数 some_string 传入，有效 如果将变量当作参数传入函数，那么它和移动的效果是一样的。
    println!("{}", some_string);
} // 函数结束, 参数 some_string 在这里释放

fn makes_copy(some_integer: i32) {
    // 一个 i32 参数 some_integer 传入，有效
    println!("{}", some_integer);
} // 函数结束, 参数 some_integer 是基本类型, 无需释放

// ------------------------- 函数返回值的所有权机制
fn main() {
    let s1 = gives_ownership();
    // gives_ownership 移动它的返回值到 s1

    let s2 = String::from("hello");
    // s2 被声明有效

    let s3 = takes_and_gives_back(s2);
    // s2 被当作参数移动, s3 获得返回值所有权
    println!("{} -{}",s1,s3); // 这是ok的
    //println!("{}-{} -{}",s1,s2,s3);   //  s2已经被释放
} // s3 无效被释放, s2 被移动, s1 无效被释放.

fn gives_ownership() -> String {
    let some_string = String::from("hello");
    // some_string 被声明有效

    return some_string;
    // some_string 被当作返回值移动出函数
}

fn takes_and_gives_back(a_string: String) -> String { 
    // a_string 被声明有效

    a_string  // a_string 被当作返回值移出函数
}

 
// --------------------------- 引用 (&) 和 租借  -------------------------------
// 引用没有所有权
// 引用只能租借（Borrow）值的所有权。
fn main() {
    let s1 = String::from("hello");
    let s2 = &s1;  // 直接等于的话,s1的资源就会被释放
    println!("s1 is {}, s2 is {}", s1, s2);
}

// 引用在函数中的传参,原本的值不会被释放 ,引用只能租借（Borrow）值的所有权。
fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

/*
这段程序不正确：因为 s2 租借的 s1 已经将所有权移动到 s3，所以 s2 将无法继续租借使用 s1 的所有权。如果需要使用 s2 使用该值，必须重新
*/
fn main() {
    let s1 = String::from("hello");
    let s2 = &s1;
    let s3 = s1;
    println!("{}", s2);
}
// 应该为
fn main() {
    let s1 = String::from("hello");
    let mut s2 = &s1;
    let s3 = s2;
    s2 = &s3; // 重新从 s3 租借所有权
    println!("{}", s2);
}